using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace TreeEx
{
	/// <summary>
	/// TreeEx User control
	/// </summary>
	public class TreeExControl : System.Windows.Forms.UserControl
	{
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		SolidBrush		_DrawBrush		= new SolidBrush(Color.Black);
		SolidBrush		_SelectBrush	= new SolidBrush(Color.Blue);
		Pen				_DrawPen		= new Pen(Color.Blue);
		Font			_DrawFont		= new Font("Times New Roman", 9);
		StringFormat	_TextFormat		= new StringFormat(StringFormatFlags.DirectionVertical);
		NodeEx			_Root;
		bool			_ShowLabels		= true;
		bool			_ShowLines		= true;
		int				_NodeWidth		= NodeEx.NODE_WIDTH;
		int				_NodeHeight		= NodeEx.NODE_HEIGHT;
		int				_LevelMargin	= NodeEx.LEVEL_MARGIN;

		#region properties
		
		public NodeEx Root
		{
			get{ return _Root; }
			set{ _Root = value; }
		}

		public Color NodeColor
		{
			get { return _DrawBrush.Color; }
			set { _DrawBrush.Color	= value; }
		}

		public Color SelectedNodeColor
		{
			get { return _SelectBrush.Color; }
			set { _SelectBrush.Color	= value; }
		}

		public Font TextFont
		{
			get { return _DrawFont; }
			set { _DrawFont	= value; }
		}

		public StringFormatFlags TextFormat
		{
			get { return _TextFormat.FormatFlags; }
			set { _TextFormat.FormatFlags	= value; }
		}

		public bool ShowLines
		{
			get { return _ShowLines; }
			set { _ShowLines	= value; }
		}

		public bool ShowLabels
		{
			get { return _ShowLabels; }
			set { _ShowLabels	= value; }
		}

		public int NodeWidth
		{
			get { return _NodeWidth; }
			set { _NodeWidth	= value; }
		}

		public int NodeHeight
		{
			get { return _NodeHeight; }
			set { _NodeHeight	= value; }
		}
		
		public int LevelMargin
		{
			get { return _LevelMargin; }
			set { _LevelMargin	= value; }
		}


		#endregion

        public void Highlight(string key, bool light)
        {
            NodeEx nd = _Root.FindNode(key);
            if (nd != null)
                nd.Highlight(light);
            Invalidate();
        }

        public void HighlightAll(bool light)
        {
            _Root.HighlightAll(light);
            Invalidate();
        }

		#region Custom events

		/// <summary>
		/// Selected Node Changed event handler type
		/// </summary>
		public delegate void SelectedNodeChangedHandler(object sender, NodeChangedEventArgs e);

		/// <summary>
		/// Selected Node Chaneged Event handler
		/// </summary>
		public event SelectedNodeChangedHandler		SelectedNodeChanged;

		/// <summary>
		/// Helper function - fires SelectedNode Event handler if valid
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnSelectedNodeChanged(NodeChangedEventArgs e) 
		{
			if(SelectedNodeChanged != null)
				SelectedNodeChanged(this, e);
		}

		#endregion

		public TreeExControl()
		{
			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();

		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if( components != null )
					components.Dispose();

				// Dispose resources
				_DrawBrush.Dispose();
				_SelectBrush.Dispose();
				_DrawPen.Dispose();
				_DrawFont.Dispose();
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			// 
			// TreeExControl
			// 
			this.BackColor = System.Drawing.Color.White;
			this.Cursor = System.Windows.Forms.Cursors.Hand;
			this.Name = "TreeExControl";
			this.Size = new System.Drawing.Size(216, 200);
			this.Resize += new System.EventHandler(this.TreeExControl_Resize);
			this.Load += new System.EventHandler(this.TreeExControl_Load);
			this.Paint += new System.Windows.Forms.PaintEventHandler(this.TreeExControl_Paint);
			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.TreeExControl_MouseDown);

		}
		#endregion

		#region Control event handlers (Paint/Resize/Draw/Mouse events) functions)

		/// <summary>
		/// Redraw tree on paint
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void TreeExControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{	
			DrawTree();
		}

		/// <summary>
		/// Redraw tree on re-size to fit to new size
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void TreeExControl_Resize(object sender, System.EventArgs e)
		{
			DrawTree();
		}

		/// <summary>
		/// Helper function
		/// </summary>
		/// <param name="node"></param>
		/// <param name="gph"></param>
		private void DrawTree(NodeEx node, Graphics gph)
		{
			if(node != null)
				node.DrawTree(gph,_DrawBrush, _DrawPen, _DrawFont);
		}

		/// <summary>
		/// Helper function
		/// </summary>
		private void DrawTree()
		{
			if(Root == null)
				return;

			Root.TotalWidth		= this.Width;
			Root.X				= this.Width / 2;
			Root.SelectBrush	= _SelectBrush;
			Root.TextFormat		= _TextFormat;
			Root.ShowLines		= ShowLines;
			Root.ShowLabels		= ShowLabels;
			Root.NodeHeight		= _NodeHeight;
			Root.NodeWidth		= _NodeWidth;
			Root.LevelMargin	= _LevelMargin;

			Graphics gph = Graphics.FromHwnd(this.Handle);
			gph.Clear(this.BackColor);
			DrawTree(Root, gph);

			// Clean up
			gph.Dispose();
		}

		/// <summary>
		/// On control load event
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void TreeExControl_Load(object sender, System.EventArgs e)
		{
			DrawTree();
		}

		/// <summary>
		/// On Mouse Down: Get selected Node - Expand/Collapse if node found
		/// Fire Selected Node change event
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void TreeExControl_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			NodeEx node = Root.GetNodeAt(e.X, e.Y);
			if(node != null)
			{
				node.Expand		= !node.Expand;
				DrawTree();

				OnSelectedNodeChanged(new NodeChangedEventArgs(node));
			}
		}

		#endregion
	}
}
